home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
haeberli
/
libgutil
/
rgn.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
13KB
|
849 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* rgn -
* Management of regions.
*
* Paul Haeberli - 1986
*/
#include "rct.h"
#include "rgn.h"
#ifdef NOTDONE
rgnrectinside(pt,rgn);
#endif
#define RGN_UNION 1
#define RGN_INTERSECT 2
#define RGN_DIFF 3
#define LEFT 1 /* don't change this!! */
#define RIGHT 0
#define OP1 1
#define OP2 2
#define BIGY 1000000
#define NINCHUNK 20
typedef struct Edge {
struct Edge *next;
int side;
int op;
int xpos;
int xmax;
int ymax;
rctlist *rect;
} Edge;
#define STATIC static
STATIC doscan();
STATIC rctlist *incorporate();
STATIC operate();
STATIC quickop();
STATIC deleteold();
STATIC rctlist *addtoactive();
STATIC addedge();
STATIC nexty();
STATIC quickunion();
STATIC Edge *newedge();
STATIC freeedge();
STATIC freeedgelist();
STATIC rctlist *newrl();
STATIC freerl();
STATIC freerectlist();
static Edge *fedges = 0;
static rctlist *frls = 0;
static Edge *active, *endactive;
static Edge *opactive;
static Edge *newopactive;
static int nop1, nop2;
Edge *newedge();
rctlist *newrl();
rctlist *addtoactive();
rctlist *incorporate();
rgn *rgnnew()
{
rgn *r;
r = (rgn *)mymalloc(sizeof(rgn));
r->domain.xmin = 0;
r->domain.ymin = 0;
r->domain.xmax = 0;
r->domain.ymax = 0;
r->rects = 0;
return r;
}
rgnfree(r)
rgn *r;
{
freerectlist(r);
free(r);
}
rgn *rgnclone(r)
rgn *r;
{
rgn *c;
rctlist *rl, *crl;;
c = rgnnew();
*c = *r;
crl = 0;
rl = r->rects;
while(rl) {
if(!crl) {
c->rects = newrl();
crl = c->rects;
} else {
crl->next = newrl();
crl = crl->next;
}
crl->rect = rl->rect;
crl->next = 0;
rl = rl->next;
}
return c;
}
rgncopy(src,dst)
rgn *src, *dst;
{
rctlist *rl, *crl;;
if(src == dst)
return;
freerectlist(dst);
*dst = *src;
crl = 0;
rl = src->rects;
while(rl) {
if(!crl) {
dst->rects = newrl();
crl = dst->rects;
} else {
crl->next = newrl();
crl = crl->next;
}
crl->rect = rl->rect;
crl->next = 0;
rl = rl->next;
}
}
rgnsetempty(r)
rgn *r;
{
freerectlist(r);
r->domain.xmin = 0;
r->domain.ymin = 0;
r->domain.xmax = 0;
r->domain.ymax = 0;
}
rgnsetrect(r,x1,y1,x2,y2)
rgn *r;
int x1, x2, y1, y2;
{
freerectlist(r);
r->rects = newrl();
r->rects->next = 0;
rctset(&r->rects->rect,x1,y1,x2,y2);
rctset(&r->domain,x1,y1,x2,y2);
}
rgnrect(r,rect)
rgn *r;
rct *rect;
{
freerectlist(r);
r->rects = newrl();
r->rects->rect = *rect;
r->rects->next = 0;
r->domain = *rect;
}
rgnequal(r1,r2)
rgn *r1, *r2;
{
rctlist *rl1, *rl2;
if(r1 == r2)
return 1;
if(!rctequal(&r1->domain,&r2->domain))
return 0;
rl1 = r1->rects;
rl2 = r2->rects;
while(rl1 && rl2) {
if(!rctequal(&rl1->rect,&rl2->rect))
return 0;
rl1 = rl1->next;
rl2 = rl2->next;
}
if(rl1 || rl2)
return 0;
else
return 1;
}
rgnempty(r)
rgn *r;
{
if(r->rects)
return 0;
else
return 1;
}
rgninside(r,x,y)
rgn *r;
int x, y;
{
rctlist *rl;
if(rgnempty(r))
return 0;
else {
rl = r->rects;
while(rl) {
if(rctinside(&rl->rect,x,y))
return 1;
rl = rl->next;
}
return 0;
}
}
rgnoffset(r,dx,dy)
rgn *r;
int dx, dy;
{
rctlist *rl;
rctoffset(&r->domain,dx,dy);
rl = r->rects;
while(rl) {
rctoffset(&rl->rect,dx,dy);
rl = rl->next;
}
}
rgnshrink(r,dx,dy)
rgn *r;
int dx, dy;
{
rgn *temp;
temp = rgnclone(r);
rgnoffset(temp,dx/2,dy/2);
rgncopy(temp,r);
rgnoffset(temp,-dx,0);
rgnintersect(temp,r,r);
rgnoffset(temp,0,-dy);
rgnintersect(temp,r,r);
rgnoffset(temp,dx,0);
rgnintersect(temp,r,r);
rgnfree(temp);
}
rgnshadow(r,dx,dy)
rgn *r;
int dx, dy;
{
rgn *temp;
temp = rgnclone(r);
rgnoffset(temp,dx,dy);
rgndiff(temp,r,r);
rgnfree(temp);
}
rgndraw(r)
rgn *r;
{
rctlist *rl;
rct temp;
rl = r->rects;
while(rl) {
temp = rl->rect;
rctshrink(&temp,1,1);
rctdraw(&temp);
rl = rl->next;
}
}
rgnfill(r)
rgn *r;
{
rctlist *rl;
rl = r->rects;
while(rl) {
rctfill(&rl->rect);
rl = rl->next;
}
}
rgnsetdomain(r)
rgn *r;
{
int xmin, xmax, ymin, ymax;
rct *d;
rctlist *rl;
rl = r->rects;
if(!rl) {
r->domain.xmin = 0;
r->domain.ymin = 0;
r->domain.xmax = 0;
r->domain.ymax = 0;
} else {
d = &r->domain;
*d = rl->rect;
while(rl) {
rctunion(&rl->rect,d,d);
rl = rl->next;
}
}
}
rgntouch(r1,r2)
rgn *r1, *r2;
{
if(rgnempty(r1))
return 0;
if(rgnempty(r2))
return 0;
if(r1->domain.xmin>(r2->domain.xmax+1))
return 0;
if(r2->domain.xmin>(r1->domain.xmax+1))
return 0;
if(r1->domain.ymin>(r2->domain.ymax+1))
return 0;
if(r2->domain.ymin>(r1->domain.ymax+1))
return 0;
return 1;
}
rgnunion(src1,src2,dst)
rgn *src1, *src2, *dst;
{
rgn *d;
if(!rgntouch(src1,src2)) {
quickunion(src1,src2,dst);
return;
}
if(rgnempty(src1)) {
rgncopy(src2,dst);
return;
}
if(rgnempty(src2)) {
rgncopy(src1,dst);
return;
}
if(rgnequal(src1,src2)) {
rgncopy(src1,dst);
return;
}
d = rgnnew();
doscan(src1,src2,d,RGN_UNION);
freerectlist(dst);
*dst = *d;
free(d);
}
rgnintersect(src1,src2,dst)
rgn *src1, *src2, *dst;
{
rgn *d;
if(!rgntouch(src1,src2)) {
rgnsetempty(dst);
return;
}
if(rgnempty(src1) || rgnempty(src2)) {
rgnsetempty(dst);
return;
}
if(rgnequal(src1,src2)) {
rgncopy(src1,dst);
return;
}
d = rgnnew();
doscan(src1,src2,d,RGN_INTERSECT);
freerectlist(dst);
*dst = *d;
free(d);
}
rgndiff(src1,src2,dst)
rgn *src1, *src2, *dst;
{
rgn *d;
if(!rgntouch(src1,src2)) {
rgncopy(src1,dst);
return;
}
if(rgnempty(src1) || rgnequal(src1,src2)) {
rgnsetempty(dst);
return;
}
if(rgnempty(src2)) {
rgncopy(src1,dst);
return;
}
d = rgnnew();
doscan(src1,src2,d,RGN_DIFF);
freerectlist(dst);
*dst = *d;
free(d);
}
STATIC doscan(src1,src2,dst,op)
rgn *src1, *src2, *dst;
int op;
{
int y;
rctlist *rl1, *rl2;
rctlist *dstend;
rl1 = src1->rects;
rl2 = src2->rects;
dst->rects = 0;
active = 0;
nop1 = nop2 = 0;
opactive = 0;
newopactive = 0;
dstend = 0;
while( (y=nexty(rl1,rl2)) != BIGY ) {
deleteold(y);
if(rl1)
rl1 = addtoactive(y,rl1,OP1);
if(rl2)
rl2 = addtoactive(y,rl2,OP2);
operate(op);
dstend = incorporate(dst,dstend,y);
}
rgnsetdomain(dst);
}
STATIC rctlist *incorporate(dst,end,y)
rgn *dst;
rctlist *end;
int y;
{
Edge *new, *old, *temp;
int x, donew;
new = newopactive;
old = opactive;
while(new || old) {
donew = 0;
if(new && old) {
if(old->xpos == new->xpos) {
if(old->xmax == new->xmax) { /* no change ? */
new->rect = old->rect;
old = old->next;
new = new->next;
} else {
old->rect->rect.ymax = y-1; /* kill old rect */
old = old->next;
donew = 1; /* make new rect */
}
} else {
if(old->xpos<new->xpos) {
old->rect->rect.ymax = y-1; /* kill old rect */
old = old->next;
} else
donew = 1; /* make new rect */
}
} else if(!new && old) {
old->rect->rect.ymax = y-1; /* kill old rect */
old = old->next;
} else if(!old && new)
donew = 1; /* make new rect */
if(donew) {
if(!end) {
end = dst->rects = newrl();
} else {
end->next = newrl();
end = end->next;
}
new->rect = end;
end->rect.xmin = new->xpos;
end->rect.ymin = y;
end->rect.xmax = new->xmax;
end->rect.ymax = y;
end->next = 0;
new = new->next;
}
}
freeedgelist(opactive);
opactive = newopactive;
newopactive = 0;
return end;
}
STATIC operate(op)
int op;
{
Edge *e, *noa;
int xpos;
int in1, in2, res, newres;
if(nop1 == 0) {
switch(op) {
case RGN_UNION:
quickop();
break;
case RGN_INTERSECT:
noa = 0;
break;
case RGN_DIFF:
noa = 0;
break;
}
return;
} else if(nop2 == 0) {
switch(op) {
case RGN_UNION:
quickop();
break;
case RGN_INTERSECT:
noa = 0;
break;
case RGN_DIFF:
quickop();
break;
}
return;
}
newopactive = 0;
e = active;
res = 0;
in1 = in2 = 0;
noa = 0;
while(e) {
xpos = e->xpos;
while(e && (e->xpos == xpos)) {
if(e->op == OP1)
in1 = e->side;
else
in2 = e->side;
e = e->next;
}
switch(op) {
case RGN_UNION:
newres = in1 | in2;
break;
case RGN_INTERSECT:
newres = in1 & in2;
break;
case RGN_DIFF:
newres = in1 & ~in2;
break;
}
if(newres != res) {
if(newres) {
if(!noa) {
noa = newopactive = newedge();
} else {
noa->next = newedge();
noa = noa->next;
}
noa->next = 0;
noa->xpos = xpos;
} else {
noa->xmax = xpos-1;
}
res = newres;
}
}
}
STATIC quickop()
{
Edge *e, *noa;
newopactive = 0;
e = active;
noa = 0;
while(e) {
if(!noa) {
noa = newopactive = newedge();
} else {
noa->next = newedge();
noa = noa->next;
}
noa->next = 0;
noa->xpos = e->xpos;
e = e->next;
noa->xmax = e->xpos-1;
e = e->next;
}
}
STATIC deleteold(y)
int y;
{
Edge *e, *temp;
e = active;
while(e && e->ymax<y) {
temp = e->next;
if(e->op == OP1)
nop1--;
else
nop2--;
freeedge(e);
e = temp;
}
active = e;
if(!e) {
endactive = 0;
return;
}
while(e->next) {
if(e->next->ymax<y) {
temp = e->next;
if(temp == endactive)
endactive = e;
e->next = temp->next;
if(temp->op == OP1)
nop1--;
else
nop2--;
freeedge(temp);
} else
e = e->next;
}
}
STATIC rctlist *addtoactive(y,rl,op)
int y;
rctlist *rl;
int op;
{
Edge *e;
while(rl && rl->rect.ymin <= y) {
e = newedge();
e->side = LEFT;
e->xpos = rl->rect.xmin;
e->ymax = rl->rect.ymax;
e->op = op;
e->rect = rl;
addedge(e);
e = newedge();
e->side = RIGHT;
e->xpos = rl->rect.xmax+1;
e->ymax = rl->rect.ymax;
e->op = op;
e->rect = rl;
addedge(e);
rl = rl->next;
if(op == OP1)
nop1 += 2;
else
nop2 += 2;
}
return rl;
}
STATIC addedge(e)
Edge *e;
{
Edge *l;
int xpos;
xpos = e->xpos;
if(!active) {
e->next = active;
active = e;
endactive = e;
return;
} else if (active->xpos >= xpos) {
e->next = active;
active = e;
return;
} else if(xpos >= endactive->xpos) {
e->next = 0;
endactive->next = e;
endactive = e;
return;
} else {
l = active;
while(l->next) {
if(l->next->xpos > xpos) {
e->next = l->next;
l->next = e;
return;
}
l = l->next;
}
e->next = 0;
l->next = e;
endactive = e;
return;
}
}
STATIC nexty(rl1,rl2)
rctlist *rl1, *rl2;
{
int y;
Edge *e;
y = BIGY;
if(rl1 && (rl1->rect.ymin<y))
y = rl1->rect.ymin;
if(rl2 && (rl2->rect.ymin<y))
y = rl2->rect.ymin;
e = active;
while(e) {
if(e->ymax<y)
y = e->ymax+1;
e = e->next;
}
return y;
}
STATIC quickunion(src1,src2,dst)
rgn *src1, *src2, *dst;
{
rctlist *rl1, *rl2, *drl, *d;
rl1 = src1->rects;
rl2 = src2->rects;
drl = 0;
while(rl1 || rl2) {
if(!rl1 && rl2) {
d = rl2;
rl2 = rl2->next;
} else if(!rl2 && rl1) {
d = rl1;
rl1 = rl1->next;
} else if(rl1->rect.ymin<rl2->rect.ymin) {
d = rl1;
rl1 = rl1->next;
} else {
d = rl2;
rl2 = rl2->next;
}
if(!drl) {
dst->rects = drl = newrl();
*drl = *d;
drl->next = 0;
} else {
drl->next = newrl();
drl = drl->next;
*drl = *d;
drl->next = 0;
}
}
rgnsetdomain(dst);
}
STATIC Edge *newedge()
{
Edge *e;
if(!fedges) {
int i;
e = (Edge *)mymalloc(NINCHUNK*sizeof(Edge));
for(i=0; i<NINCHUNK; i++)
freeedge(e++);
}
e = fedges;
fedges = fedges->next;
return e;
}
STATIC freeedge( e )
Edge *e;
{
if( e ) {
e->next = fedges;
fedges = e;
}
}
STATIC freeedgelist(edges)
Edge *edges;
{
Edge *e, *ne;
e = edges;
while(e) {
ne = e->next;
freeedge(e);
e = ne;
}
}
STATIC rctlist *newrl()
{
rctlist *rl;
if(!frls) {
int i;
rl = (rctlist *)mymalloc(NINCHUNK*sizeof(rctlist));
for(i=0; i<NINCHUNK; i++)
freerl(rl++);
}
rl = frls;
frls = frls->next;
return rl;
}
STATIC freerl( rl )
rctlist *rl;
{
if( rl ) {
rl->next = frls;
frls = rl;
}
}
STATIC freerectlist(r)
rgn *r;
{
rctlist *rl, *nrl;
rl = r->rects;
while(rl) {
nrl = rl->next;
freerl(rl);
rl = nrl;
}
r->rects = 0;
}